package com.sz.biz.app.web.api.system;

import com.sz.biz.app.constants.WebConstants;
import com.sz.biz.app.web.BaseController;
import com.sz.common.base.dto.ResultDto;
import com.sz.common.base.exception.Exceptions;
import com.sz.common.core.constants.MessagesCodes;
import com.sz.common.core.constants.SysErrorCodes;
import com.sz.common.core.system.dto.FileInfoDto;
import com.sz.common.core.system.entity.SysFile;
import com.sz.common.core.system.service.SysFileService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

/**
 * Function: SysFileController <br>
 * Author: wentao.chang <br>
 * Date: 2016-12-13 20:40:00
 */
@Controller
@RequestMapping("/api/v1/sys/files")
@Api(description = " ", tags = "103、文件上传")
public class SysFileController extends BaseController {
    @Autowired
    private SysFileService sysFileService;

    /**
     * 图片类
     */
    private static final List<String> PICCONTENT = new ArrayList<>();
    /**
     * 文件类
     */
    private static final List<String> FILECONTENT = new ArrayList<>();

    /**
     * 文件扩展名白名单
     */
    private static final List<String> FILEEXTS = new ArrayList<>();

    static {
        /*  常见的文件头
        // images
        mFileTypes.put("FFD8FFE1", "jpg");
        mFileTypes.put("89504E47", "png");
        mFileTypes.put("47494638", "gif");
        mFileTypes.put("49492A00", "tif");
        mFileTypes.put("424D", "bmp");
        // others
        mFileTypes.put("41433130", "dwg"); // CAD
        mFileTypes.put("38425053", "psd");
        mFileTypes.put("7B5C727466", "rtf"); // 日记本
        mFileTypes.put("3C3F786D6C", "xml");
        mFileTypes.put("68746D6C3E", "html");
        mFileTypes.put("44656C69766572792D646174653A", "eml"); // 邮件
        mFileTypes.put("D0CF11E0", "doc");
        mFileTypes.put("5374616E64617264204A", "mdb");
        mFileTypes.put("252150532D41646F6265", "ps");
        mFileTypes.put("255044462D312E", "pdf");
        mFileTypes.put("504B0304", "docx");
        mFileTypes.put("52617221", "rar");
        mFileTypes.put("57415645", "wav");
        mFileTypes.put("41564920", "avi");
        mFileTypes.put("2E524D46", "rm");
        mFileTypes.put("000001BA", "mpg");
        mFileTypes.put("000001B3", "mpg");
        mFileTypes.put("6D6F6F76", "mov");
        mFileTypes.put("3026B2758E66CF11", "asf");
        mFileTypes.put("4D546864", "mid");
        mFileTypes.put("1F8B08", "gz");
        mFileTypes.put("4D5A9000", "exe/dll");
        mFileTypes.put("75736167", "txt");
        */

        //必须使用长度相同的4位
        PICCONTENT.add("FFD8");
        FILEEXTS.add("jpg");
        FILEEXTS.add("jpeg");

        //"png"
        PICCONTENT.add("8950");
        FILEEXTS.add("png");

        //"bmp"
        PICCONTENT.add("424D");
        FILEEXTS.add("bmp");

        //"tiff"
        PICCONTENT.add("4D4D");
        FILEEXTS.add("tiff");

        //"tif"
        PICCONTENT.add("4949");
        FILEEXTS.add("tif");

        //PICCONTENT.add("4749");//gif
        //DOCX 504B、DOC D0CF、DOTX 504B、DOT D0CF、XLS D0CF、XLTX 504B、XLT D0CF、XLSX 504B
        FILECONTENT.addAll(PICCONTENT);

        //pdf
        FILECONTENT.add("2550");
        FILEEXTS.add("pdf");

        //DOCX DOTX XLTX XLSX
        FILECONTENT.add("504B");
        FILEEXTS.add("docx");
        // FILEEXTS.add("dotx");
        // FILEEXTS.add("xltx");
        FILEEXTS.add("xlsx");

        //DOC DOT XLS XLT
        FILECONTENT.add("D0CF");
        FILEEXTS.add("doc");
        //FILEEXTS.add("dot");
        // FILEEXTS.add("xlt");
        FILEEXTS.add("xls");
    }

    @ApiOperation(value = "上传文件", notes = "-")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "type", value = "文件类型，pic、file",
                    required = true, dataType = "string", paramType = "path")})
    @RequestMapping(value = "/upload/{type}", method = RequestMethod.POST)
    public
    @ResponseBody
    ResultDto uploadFile(MultipartFile file, @PathVariable String type) throws IOException {
        if (file != null && !file.isEmpty()) {
            SysFile sysFile;
            String filename = file.getOriginalFilename();
            byte[] content = file.getBytes();
            byte[] contentTypeByte = ArrayUtils.subarray(content, 0, 2);
            String[] filenames = filename.split("\\.");
            if (!FILEEXTS.contains(filenames[filenames.length - 1].toLowerCase())) {
                throw Exceptions.bizException(SysErrorCodes.ERROR_FILE_NOT_SAFE);
            }
            String contentType = bytesToHexString(contentTypeByte);
            checkFileType(type, contentType);
            try {
                sysFile = sysFileService.uploadFile(0, "", filename, file.getContentType(), "", file);
            } catch (Exception e) {
                this.logger.error("upload file failed", e);
                ResultDto dto = new ResultDto();
                dto.setErrorCode(-1);
                dto.setMsg(e.getMessage());
                return dto;
            }
            ResultDto dto = new ResultDto();
            dto.setErrorCode(0);
            dto.setMsg(messageSource.getMessage(MessagesCodes.FILE_UPLOAD_SUCCESS, null));
            dto.setData(new FileInfoDto(sysFile.getFileId(), filename, file.getContentType(), sysFile.getFileLocation()));
            return dto;
        } else {
            throw Exceptions.bizException(SysErrorCodes.ERROR_FILE_IS_EMPTY);
        }
    }

    private void checkFileType(String type, String contentType) {
        if (WebConstants.SysFile.PIC.equals(type) && !PICCONTENT.contains(contentType)) {
            throw Exceptions.bizException(SysErrorCodes.ERROR_FILE_ILLEGAL);
        }
        if (WebConstants.SysFile.FILE.equals(type) && !FILECONTENT.contains(contentType)) {
            throw Exceptions.bizException(SysErrorCodes.ERROR_FILE_ILLEGAL);
        }
    }

    /**
     * 将要读取文件头信息的文件的byte数组转换成string类型表示
     *
     * @param src 要读取文件头信息的文件的byte数组
     * @return 文件头信息
     */
    private static String bytesToHexString(byte[] src) {
        StringBuilder builder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        String hv;
        for (byte aSrc : src) {
            // 以十六进制（基数 16）无符号整数形式返回一个整数参数的字符串表示形式，并转换为大写
            hv = Integer.toHexString(aSrc & 0xFF).toUpperCase();
            if (hv.length() < 2) {
                builder.append(0);
            }
            builder.append(hv);
        }
        return builder.toString();
    }

    @ApiOperation(value = "（弃用）下载文件：文件流的形式，可以用于html的src预览", notes = "-")
    @RequestMapping(value = "/download/{fileid}", method = RequestMethod.GET)
    public void downloadFile(@PathVariable String fileid, HttpServletResponse response)
            throws IOException {
        SysFile sysFile = sysFileService.getFileContent(fileid);
        if (sysFile == null) {
            throw Exceptions.bizException(SysErrorCodes.ERROR_FILE_NOT_FOUND, fileid);
        }
        downloadFile(response, sysFile);
    }


    @ApiOperation(value = "（弃用）下载文件：当做附件下载原始文件", notes = "-")
    @RequestMapping(value = "/download/{fileid}/orgin", method = RequestMethod.GET)
    public void downloadOrginFile(@PathVariable String fileid, HttpServletRequest request, HttpServletResponse response)
            throws IOException {
        SysFile sysFile = sysFileService.getFileContent(fileid);
        if (sysFile == null) {
            throw Exceptions.bizException(SysErrorCodes.ERROR_FILE_NOT_FOUND, fileid);
        }
        String encodedfileName = getFileEncoding(request, sysFile);
        response.setHeader("Content-Disposition", "attachment;fileName=" + encodedfileName);
        downloadFile(response, sysFile);
    }

    private String getFileEncoding(HttpServletRequest request, SysFile sysFile) throws UnsupportedEncodingException {
        String encodedfileName;
        String agent = request.getHeader("USER-AGENT");
        if (null != agent && agent.contains(WebConstants.SysFile.MSIE)) {//IE
            encodedfileName = java.net.URLEncoder.encode(sysFile.getFileName(), WebConstants.SysFile.UTF_8);
        } else if (null != agent && agent.contains(WebConstants.SysFile.MOZILLA)) {
            encodedfileName = new String(sysFile.getFileName().getBytes(WebConstants.SysFile.UTF_8), WebConstants.SysFile.ISO_8859_1);
        } else {
            encodedfileName = java.net.URLEncoder.encode(sysFile.getFileName(), WebConstants.SysFile.UTF_8);
        }
        return encodedfileName;
    }

    private void downloadFile(HttpServletResponse response, SysFile sysFile) throws IOException {
        OutputStream fos = response.getOutputStream();
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        bos.write(sysFile.getFileContent(), 0, sysFile.getFileSize().intValue());
        bos.flush();
        fos.close();
        bos.close();
    }
}
